#include "snake.h"


int  Snake::MAX_HEIGHT = 20;
int  Snake::MAX_WIDTH = 20;
int  Snake::MIN_HEIGHT = 0;
int  Snake::MIN_WIDTH = 0;
char Snake::SPRITE_TAIL = '+';
char Snake::SPRITE_HEAD = 'O';
bool Snake::COLISION;

Snake::Snake(int x, int y, DIRECTION init_head)
	:size(1), heading(init_head)
{
	Segment temp;
	temp.cur_pos.first = x;
	temp.cur_pos.second = y;
	temp.old_pos.first = x;
	temp.old_pos.first = y - 1;
	head = new Segment(temp);
}
Snake::~Snake()
{
	Util_Delete(head);
	delete head;
}
void Snake::Util_Delete(Segment *& root)
{
	if(root->next_segment != NULL)
	{
		Util_Delete(root->next_segment);
		delete root->next_segment;
	}
}
pair<int,int> Snake::Head() const
{
	return head->cur_pos;
}
void Snake::SetHeading(DIRECTION dir)
{
	heading = dir;
}
void Snake::AddSegment()
{
	Util_AddSegment(head);
	size++;
}
void Snake::Util_AddSegment(Segment *& root)
{
	if(root->next_segment != NULL)
	{
		Util_AddSegment(root->next_segment);
	}
	else
	{
		Segment temp;
		temp.cur_pos.first = root->old_pos.first;
		temp.cur_pos.second = root->old_pos.second;
		temp.old_pos.first = root->old_pos.first;
		temp.old_pos.first = root->old_pos.second - 1;
		root->next_segment = new Segment;
	}
}
void Snake::Update()
{
	head->old_pos = head->cur_pos;
	switch(heading)
	{
	case UP:    head->cur_pos.second = ( head->cur_pos.second - 1 < MIN_HEIGHT  ) ? MAX_HEIGHT: head->cur_pos.second - 1; break;
	case DOWN:  head->cur_pos.second = ( head->cur_pos.second + 1 > MAX_HEIGHT ) ? MIN_HEIGHT : head->cur_pos.second + 1; break;
	case LEFT:  head->cur_pos.first  = ( head->cur_pos.first - 1 < MIN_WIDTH ) ? MAX_WIDTH : head->cur_pos.first - 1; break;
	case RIGHT: head->cur_pos.first  = ( head->cur_pos.first + 1 > MAX_WIDTH ) ? MIN_WIDTH : head->cur_pos.first + 1; break;
	}

	//TODO: call to a function that updates all attached segment;
	Util_Update(head);
}
void Snake::Util_Update(Segment *& root)
{
	if(root->next_segment != NULL)
	{
		root->next_segment->old_pos = root->next_segment->cur_pos;
		root->next_segment->cur_pos = root->old_pos;
		Util_Update(root->next_segment);
	}
}
void Snake::Draw() const
{
	//draw the head
	//set the cursor to head position
	ixion::SetCursorPos(head->cur_pos.first,head->cur_pos.second);
	std::cout << SPRITE_HEAD;
	
	//draw old head as a tail
	ixion::SetCursorPos(head->old_pos.first,head->old_pos.second);
	std::cout << SPRITE_TAIL;
	
	//erase the tail
	//locate the tail
	Segment * tail = head;
	while(tail->next_segment != NULL)
	{
		tail = tail->next_segment;
	}
	if(tail != head)
	{
		ixion::SetCursorPos(tail->old_pos.first,tail->old_pos.second);
		std::cout << " ";
	}
	
}

bool Snake::CheckForColision() const
{
	COLISION = false;
	Segment * segPtr = head->next_segment;
	while(segPtr != NULL)
	{
		if(segPtr->cur_pos == head->cur_pos)
			COLISION = true;
		segPtr = segPtr->next_segment;
	}
	
	return COLISION;
}